<script setup lang="ts">
import { marked } from 'marked'
import { request } from '~/utils/http/factory'
import type { CardDetail } from '~/components/index/CardDetailModal.vue'

definePageMeta({ layout: 'home' })

const { $toast } = useNuxtApp()
const { loggedIn } = useAuthSession()
const route = useRoute()
const router = useRouter()

// ── Types ──

interface CardRef {
  id: number
  title: string
  type: string
  description: string | null
  aspectRatio: number | null
  coverUrl: string | null
  sortOrder: number
}

interface ArticleDetail {
  id: number
  title: string
  content: string
  summary: string | null
  cover: string | null
  status: 'draft' | 'published'
  createdAt: Date
  updatedAt: Date
  cards: CardRef[]
}

// ── State ──

const article = ref<ArticleDetail | null>(null)
const loading = ref(true)
const notFound = ref(false)

// ── Edit dialog ──

const editVisible = ref(false)

// ── Card detail modal ──

const showCardDetail = ref(false)
const detailCard = ref<CardDetail | null>(null)

function onCardClick(card: CardRef) {
  detailCard.value = {
    id: card.id,
    type: card.type as CardDetail['type'],
    title: card.title,
    description: card.description ?? undefined,
    aspectRatio: card.aspectRatio ?? 0.75,
    image: card.coverUrl ?? undefined,
  }
  showCardDetail.value = true
}

// ── Confirm delete ──

const confirmShow = ref(false)

// ── Fetch ──

async function fetchArticle() {
  loading.value = true
  const id = route.params.id as string
  try {
    const raw = await request<{ code: number; data: ArticleDetail }>(`/api/articles/${id}`)
    if (!raw.data) {
      notFound.value = true
      return
    }
    article.value = raw.data
  } catch {
    notFound.value = true
  } finally {
    loading.value = false
  }
}

// ── Actions ──

function openEdit() {
  if (!article.value) return
  editVisible.value = true
}

function onArticleSaved() {
  fetchArticle()
}

async function handleDelete() {
  try {
    await request(`/api/articles/${article.value!.id}`, { method: 'DELETE' })
    $toast.success('文章已删除')
    router.push('/articles')
  } catch (e: any) {
    $toast.error(e?.data?.message || e?.message || '删除失败')
  }
}

function goBack() {
  router.push('/articles')
}

function formatDate(d: Date | string) {
  return new Date(d).toLocaleDateString('zh-CN', {
    year: 'numeric',
    month: 'long',
    day: 'numeric',
  })
}

const contentHtml = computed(() => {
  if (!article.value?.content) return ''
  return marked(article.value.content, { breaks: true }) as string
})

// ── Init ──

onMounted(() => {
  fetchArticle()
})

watch(() => route.params.id, () => {
  fetchArticle()
})
</script>

<template>
  <div class="detail-page">
    <!-- Loading -->
    <div v-if="loading" class="loading-state">
      <p class="loading-text">加载中…</p>
    </div>

    <!-- 404 -->
    <div v-else-if="notFound" class="not-found-state">
      <p class="not-found-text">文章不存在</p>
      <button class="btn-back" @click="goBack">返回列表</button>
    </div>

    <!-- Article -->
    <template v-else-if="article">
      <!-- Nav -->
      <div class="detail-nav">
        <button class="btn-back" @click="goBack">
          ← 返回列表
        </button>
        <div v-if="loggedIn" class="nav-actions">
          <button class="btn-edit" @click="openEdit">编辑</button>
          <button class="btn-delete" @click="confirmShow = true">删除</button>
        </div>
      </div>

      <!-- Header -->
      <header class="detail-header">
        <div class="header-meta">
          <span
            class="status-badge"
            :class="article.status"
          >
            {{ article.status === 'published' ? '已发布' : '草稿' }}
          </span>
          <span class="header-date">{{ formatDate(article.createdAt) }}</span>
        </div>
        <h1 class="detail-title">{{ article.title }}</h1>
        <p v-if="article.summary" class="detail-summary">{{ article.summary }}</p>
      </header>

      <!-- Cover -->
      <div v-if="article.cover" class="detail-cover">
        <img :src="article.cover" :alt="article.title" />
      </div>

      <!-- Content -->
      <div class="detail-content">
        <div class="detail-content-body" v-html="contentHtml" />
      </div>

      <!-- Related Cards -->
      <div v-if="article.cards.length > 0" class="related-cards">
        <h2 class="related-title">关联卡片</h2>
        <div class="cards-grid">
          <div
            v-for="card in article.cards"
            :key="card.id"
            class="card-item"
            @click="onCardClick(card)"
          >
            <div class="card-cover">
              <img
                v-if="card.coverUrl"
                :src="card.coverUrl"
                :alt="card.title"
              />
              <div v-else class="card-cover-placeholder" />
            </div>
            <div class="card-info">
              <span class="card-type-badge">{{ card.type }}</span>
              <h3 class="card-name">{{ card.title }}</h3>
              <p v-if="card.description" class="card-desc">{{ card.description }}</p>
            </div>
          </div>
        </div>
      </div>
    </template>

    <!-- Edit Dialog -->
    <ArticleFormDialog
      :visible="editVisible"
      mode="edit"
      :article="article"
      @update:visible="editVisible = $event"
      @saved="onArticleSaved"
    />

    <!-- Card Detail Modal -->
    <IndexCardDetailModal
      :visible="showCardDetail"
      :card="detailCard"
      :categories="[]"
      @update:visible="(v: boolean) => showCardDetail = v"
    />

    <!-- Confirm Delete -->
    <BoDialog v-model:show="confirmShow">
      <div class="confirm-dialog">
        <p class="confirm-msg">确定删除「{{ article?.title }}」吗？此操作不可撤销。</p>
        <div class="confirm-actions">
          <button class="btn-cancel" @click="confirmShow = false">取消</button>
          <button class="btn-save danger" @click="handleDelete">确认删除</button>
        </div>
      </div>
    </BoDialog>
  </div>
</template>

<style scoped>
.detail-page {
  padding: 32px 0 64px;
  flex: 1;
  max-width: 800px;
  margin: 0 auto;
  width: 100%;
}

/* ── Loading / 404 ── */

.loading-state,
.not-found-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 120px 0;
  gap: 16px;
}

.loading-text,
.not-found-text {
  font-size: 15px;
  color: #6c6a64;
}

.not-found-text {
  font-size: 18px;
}

/* ── Nav ── */

.detail-nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 28px;
}

.btn-back {
  padding: 6px 16px;
  border: 1px solid #e6dfd8;
  border-radius: 8px;
  background: #faf9f5;
  font-size: 13px;
  color: #6c6a64;
  cursor: pointer;
  transition: all 0.15s;
}

.btn-back:hover {
  background: #efe9de;
}

.nav-actions {
  display: flex;
  gap: 8px;
}

.btn-edit {
  padding: 6px 14px;
  border: 1px solid #e6dfd8;
  border-radius: 6px;
  background: #fff;
  font-size: 13px;
  color: #6c6a64;
  cursor: pointer;
  transition: all 0.15s;
}

.btn-edit:hover {
  border-color: #cc785c;
  color: #cc785c;
}

.btn-delete {
  padding: 6px 14px;
  border: 1px solid #e6dfd8;
  border-radius: 6px;
  background: #fff;
  font-size: 13px;
  color: #6c6a64;
  cursor: pointer;
  transition: all 0.15s;
}

.btn-delete:hover {
  border-color: #c64545;
  color: #c64545;
}

/* ── Header ── */

.detail-header {
  margin-bottom: 24px;
}

.header-meta {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 12px;
}

.status-badge {
  font-size: 11px;
  padding: 3px 10px;
  border-radius: 4px;
  font-weight: 500;
}

.status-badge.published {
  background: #d4edda;
  color: #2d6a4f;
}

.status-badge.draft {
  background: #efe9de;
  color: #8b7e6a;
}

.header-date {
  font-size: 13px;
  color: #b8b2a6;
}

.detail-title {
  font-family: var(--font-serif, 'Noto Serif SC', serif);
  font-size: 32px;
  font-weight: 600;
  color: #141413;
  margin: 0 0 10px;
  line-height: 1.3;
}

.detail-summary {
  font-size: 16px;
  color: #6c6a64;
  margin: 0;
  line-height: 1.6;
}

/* ── Cover ── */

.detail-cover {
  margin-bottom: 28px;
  border-radius: 12px;
  overflow: hidden;
}

.detail-cover img {
  width: 100%;
  max-height: 420px;
  object-fit: cover;
  display: block;
}

/* ── Content (Markdown rendered) ── */

.detail-content {
  font-size: 16px;
  line-height: 1.75;
  color: #3d3d3a;
}

/* Rendered markdown content styles */
.detail-content-body {
  font-family: var(--font-body, inherit);
  color: #3d3d3a;
  font-size: 16px;
  line-height: 1.75;
}

.detail-content-body :deep(h1),
.detail-content-body :deep(h2),
.detail-content-body :deep(h3),
.detail-content-body :deep(h4),
.detail-content-body :deep(h5),
.detail-content-body :deep(h6) {
  font-family: var(--font-serif, 'Noto Serif SC', serif);
  color: #141413;
  margin-top: 1.5em;
  margin-bottom: 0.5em;
}

.detail-content-body :deep(a) {
  color: #cc785c;
}

.detail-content-body :deep(blockquote) {
  border-left-color: #cc785c;
  color: #6c6a64;
}

.detail-content-body :deep(code) {
  background: #efe9de;
  color: #a9583e;
  padding: 2px 6px;
  border-radius: 4px;
  font-size: 0.9em;
}

.detail-content-body :deep(pre) {
  background: #181715;
  border-radius: 8px;
}

.detail-content-body :deep(img) {
  border-radius: 8px;
}

.detail-content-body :deep(table) {
  border-collapse: collapse;
  width: 100%;
}

.detail-content-body :deep(th),
.detail-content-body :deep(td) {
  border: 1px solid #e6dfd8;
  padding: 8px 12px;
  text-align: left;
}

.detail-content-body :deep(th) {
  background: #efe9de;
  font-weight: 500;
}

/* ── Related Cards ── */

.related-cards {
  margin-top: 48px;
  padding-top: 32px;
  border-top: 1px solid #e6dfd8;
}

.related-title {
  font-family: var(--font-serif, 'Noto Serif SC', serif);
  font-size: 20px;
  font-weight: 500;
  color: #141413;
  margin: 0 0 20px;
}

.cards-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 16px;
}

.card-item {
  background: #faf9f5;
  border: 1px solid #e6dfd8;
  border-radius: 10px;
  overflow: hidden;
  transition: box-shadow 0.15s;
  cursor: pointer;
}

.card-item:hover {
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
}

.card-cover {
  aspect-ratio: 1.5;
  overflow: hidden;
  background: #efe9de;
}

.card-cover img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.card-cover-placeholder {
  width: 100%;
  height: 100%;
  background: linear-gradient(135deg, #efe9de, #e8e0d2);
}

.card-info {
  padding: 12px;
}

.card-type-badge {
  font-size: 10px;
  padding: 2px 7px;
  background: #efe9de;
  color: #8b7e6a;
  border-radius: 3px;
  text-transform: uppercase;
}

.card-name {
  font-size: 14px;
  font-weight: 500;
  color: #141413;
  margin: 6px 0 4px;
}

.card-desc {
  font-size: 12px;
  color: #8b7e6a;
  margin: 0;
  line-height: 1.4;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* ── Confirm Dialog (shared button styles) ── */

.btn-cancel {
  padding: 8px 20px;
  border: 1px solid #e6dfd8;
  border-radius: 8px;
  background: #fff;
  font-size: 14px;
  color: #6c6a64;
  cursor: pointer;
}

.btn-cancel:hover {
  background: #f5f0e8;
}

.btn-save {
  padding: 8px 20px;
  border: none;
  border-radius: 8px;
  background: #cc785c;
  font-size: 14px;
  color: #fff;
  cursor: pointer;
  transition: background 0.15s;
}

.btn-save:hover {
  background: #a9583e;
}

.btn-save:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.btn-save.danger {
  background: #c64545;
}

.btn-save.danger:hover {
  background: #a33;
}

/* ── Confirm Dialog ── */

.confirm-dialog {
  background: #fff;
  border-radius: 12px;
  padding: 24px;
  min-width: 320px;
}

.confirm-msg {
  font-size: 15px;
  color: #3d3d3a;
  margin: 0 0 20px;
}

.confirm-actions {
  display: flex;
  justify-content: flex-end;
  gap: 12px;
}

/* ── Responsive ── */

@media (max-width: 768px) {
  .detail-page {
    padding: 20px 16px 48px;
  }

  .detail-title {
    font-size: 24px;
  }

  .cards-grid {
    grid-template-columns: 1fr;
  }
}
</style>
